package com.zhwei.gulimall.order.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rabbitmq.client.Channel;
import com.zhwei.common.utils.PageUtils;
import com.zhwei.common.utils.Query;
import com.zhwei.gulimall.order.dao.OrderItemDao;
import com.zhwei.gulimall.order.entity.OrderEntity;
import com.zhwei.gulimall.order.entity.OrderItemEntity;
import com.zhwei.gulimall.order.entity.OrderReturnReasonEntity;
import com.zhwei.gulimall.order.service.OrderItemService;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Map;


@RabbitListener(queues = {"hello-java.queue"})
@Service("orderItemService")
public class OrderItemServiceImpl extends ServiceImpl<OrderItemDao, OrderItemEntity> implements OrderItemService {

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderItemEntity> page = this.page(
                new Query<OrderItemEntity>().getPage(params),
                new QueryWrapper<OrderItemEntity>()
        );

        return new PageUtils(page);
    }

    //假设在这里来监听
//    @RabbitListener(queues = {"hello-java.queue"})
    public void reciveMessage(Object message){

        System.out.println("接收到消息内容："+message+"===> 类型："+ message.getClass()+"========>");
    }

    /**
     * 声明所有需要监听的队列，数组，可以监听多个queue
     * 1. Message message 原生
     * 2. 第二个参数可以把你要转换的对象，泛型，不用手动转换了
     * 3. 第三个参数可以加 通道。当前传输数据的通道
     * queue可以很多人来监听，但是只能有一个人收到，队列会删除。
     * 场景：
     *  1. 订单服务启动多个，多个实例，那会监听 ，测试结果：同一个消息 只能一个人收到
     *  2. 模拟接收到一个消息之后，假设处理时间场，处理期间是否能收到消息？ 测试结果：只有当前消息处理完之后才能接收下一个消息。
     *  3. RabbitHandler只能标注在方法上的用法。主要场景是因为这个类可以监听指定的queue,但是可以有若干方法来处理对应的消息，
     *  比如：这个queue里面有两种类型的消息，一种是：OrderReturnReasonEntity，另外一种是：OrderEntity
     */
   //@RabbitListener(queues = {"hello-java.queue"}) //把这个标注到类上面去
    @RabbitHandler
    public void reciveMessage(Message message, OrderReturnReasonEntity rentity, Channel channel){
        //byte[] body = message.getBody(); //消息体
        //System.out.println("字节数组转换成字符串： "+new String(body));
        System.out.println("接收到退货原因："+rentity.getName());
        //当开启了手到确实消息模式之后，就可以通过通道来调用basicAck()方法来确认消息
        //手到确认的时候需要传这个id，这个是通道内自测的一个id
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        try {
            // 第一个参数channel中的一个自增id，
            // 第二个参数是表示 是否批量确认。
            System.out.println("deliveryTag====="+deliveryTag);
            //再来做个模拟，比如偶数的我们收货，而奇数的我们拒绝收货
            if(deliveryTag % 2 == 0){
                channel.basicAck(deliveryTag, false);  //签收
            }else{
                //拒绝
                //basicNack: 参数1通道中消息id, 参数2：是否批量处理，参数3：表示拒签之后，是否将消息重新入队列，false则会丢弃
                channel.basicNack(deliveryTag,false, false);
                //这个方法和上面一个相似，只有两个参数，第二个参数表示是否批量处理，默认丢弃
                //channel.basicReject(deliveryTag, false);
            }
        } catch (IOException e) {
            e.printStackTrace();
            //注意比如网络或者通道断开，可能也确认不了，但是实际又是被处理过了消息，所以这个catch里面也可以通过其他方式
            // 比如来更新数据库中的记录表示已经处理过了，下次要再次发消息时就不会重新获取该消息进行再次处理
        }

    }
    //可以看到这个方法专门用来接收消息类型是：OrderEntity对象的消息
    @RabbitHandler
    public void reciveMessage2(OrderEntity orderEntity){
        System.out.println("接收到订单对象："+orderEntity.getOrderSn());
    }

}